/****************************************************************************/
/* NAME:           TSC_2046.c                                               */
/* PURPOSE:        Driver for touch pad tsc_2046                            */
/* CREATED_BY:     Vyx                                                      */
/* CREATION_DATE:  03/08/2012                                               */
/************************************** (C) Copyright 2012 AquaLink *********/

#include "stm32f10x.h"
#include "TSC_2046.h"
#include "stdio.h"

void GetScreenZone()
{
  uint16_t X = 0;
  uint16_t Y = 0;
  uint16_t temp = 0;

  X = TSC2046_MeasureX();
  Y = TSC2046_MeasureY();
  temp = TSC2046_ReadAmbiantTemp();

  X = X & 0xFFF;
  Y = Y & 0xFFF;

  printf("X = %d, Y = %d, T = %d\r\n", X, Y, temp);

  SpiDelay(100000);
}

/**
 * @brief  Init driver
 * @param  None
 * @retval None
 */
void TSC2046_Init()
{
  EXTI_InitTypeDef EXTI_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the EXTI9_5 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn  ;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource6);

  /* Configure Key Button EXTI Line to generate an interrupt on falling edge */
  EXTI_InitStructure.EXTI_Line = EXTI_Line6;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  TSC2046_SPI_config();
}

/**
 * @brief  Init spi periph
 * @param  None
 * @retval None
 */
void TSC2046_SPI_config()
{
  SPI_InitTypeDef   SPI_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

  SPI_InitStructure.SPI_Direction         = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode              = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize          = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL              = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CPHA              = SPI_CPHA_1Edge;
  SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
  //SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
  SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial     = 7;
  SPI_Init(SPI1,&SPI_InitStructure);

  SPI_Cmd(SPI1,ENABLE);
}

/**
 * @brief  Write byte on Spi and return response
 * @param  Data to be write
 * @retval Data read
 */
unsigned char TSC2046_WriteByte(unsigned char data)
{
  unsigned char Data = 0;

  /* Wait until the transmit buffer is empty */
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);

  /* Send the byte */
  SPI_I2S_SendData(SPI1,data);

  /* Wait until a data is received */
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET);
  /*Get the received data */
  Data = SPI_I2S_ReceiveData(SPI1);

  /* Return the shifted data */
  return Data;
}

void SpiDelay(unsigned int DelayCnt)
{
  unsigned int i;

  for(i=0;i<DelayCnt;i++);
}

/**
 * @brief  Read current temperature build in tsc2046
 * @param  None
 * @retval Temp read
 */
uint16_t TSC2046_ReadAmbiantTemp()
{
  uint16_t temp = 0;

  /* chip select low */
  SPI_TOUCH_CS_LOW();

  SpiDelay(10);

  /* write command to read temp */
  TSC2046_WriteByte(0x80);

  SpiDelay(10);

  temp = TSC2046_WriteByte(0x00);
  temp <<= 8;
  temp += TSC2046_WriteByte(0x00);

  SpiDelay(10);

  /* chip select high */
  SPI_TOUCH_CS_HIGH();

  temp = temp >> 3;

  return (temp);
}

/**
 * @brief  Read X pressed position
 * @param  None
 * @retval Raw X position
 */
uint16_t TSC2046_ReadRawX(void)
{
  uint16_t x = 0;

  SPI_TOUCH_CS_LOW();

  SpiDelay(10);

  TSC2046_WriteByte(0x90);

  SpiDelay(10);

  x = TSC2046_WriteByte(0x00);
  x <<= 8;
  x += TSC2046_WriteByte(0x00);

  SpiDelay(10);

  SPI_TOUCH_CS_HIGH();

  x  = x >> 3;

  return (x);
}

/**
 * @brief  Read Y pressed position
 * @param  None
 * @retval Raw Y position
 */
uint16_t TSC2046_ReadRawY(void)
{
  uint16_t y = 0;

  SPI_TOUCH_CS_LOW();

  SpiDelay(10);

  TSC2046_WriteByte(0xD0);

  SpiDelay(10);

  y = TSC2046_WriteByte(0x00);
  y <<= 8;
  y += TSC2046_WriteByte(0x00);

  SpiDelay(10);

  SPI_TOUCH_CS_HIGH();

  y  = y >> 3;

  return (y);
}

/**
 * @brief  Read virtual value of X in pixel
 * @param  None
 * @retval X value
 */
int32_t TSC2046_MeasureX(void)
{
  unsigned char t         = 0;
  unsigned char t1        = 0;
  unsigned char count     = 0;
  uint32_t databuffer[10] = {5,7,9,3,2,6,4,0,3,1};
  uint16_t temp           = 0;
  int32_t  X              = 0;

  while(count < 10)
  {
    databuffer[count] = TSC2046_ReadRawX();
    count++;
  }

  if( count == 10)
  {
    do
    {
      t1 = 0;

      for(t=0; t < count-1; t++)
      {
        if(databuffer[t] > databuffer[t+1])
        {
          temp            = databuffer[t+1];
          databuffer[t+1] = databuffer[t];
          databuffer[t]   = temp;
          t1              = 1;
        }
      }
    }
    while(t1);

    X = (databuffer[3]+databuffer[4]+databuffer[5])/3;
  }

  return (X);
}

/**
 * @brief  Read virtual value of Y in pixel
 * @param  None
 * @retval Y value
 */
int32_t TSC2046_MeasureY(void)
{
  unsigned char t         = 0;
  unsigned char t1        = 0;
  unsigned char count     = 0;
  uint32_t databuffer[10] = {5,7,9,3,2,6,4,0,3,1};
  uint16_t temp           = 0;
  int32_t  Y              = 0;

  while(count < 10)
  {
    databuffer[count] = TSC2046_ReadRawY();
    count++;
  }

  if(count==10)
  {
    do
    {
      t1 = 0;

      for(t=0; t < count-1; t++)
      {
        if(databuffer[t] > databuffer[t+1])
        {
          temp            = databuffer[t+1];
          databuffer[t+1] = databuffer[t];
          databuffer[t]   = temp;
          t1              = 1;
        }
      }
    }
    while(t1);

    Y = (databuffer[3]+databuffer[4]+databuffer[5])/3;
  }

  return (Y);
}
